/**
 * Copyright 2010-present Facebook.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.internal;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import com.facebook.FacebookException;
import com.facebook.android.Util;
import com.facebook.widget.FacebookDialog;
import com.facebook.widget.WebDialog;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.EnumSet;

/**
 * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
 * any of the classes in this package is unsupported, and they may be modified or removed without warning at
 * any time.
 *
 * This dialog is used as a fallback when a native FacebookDialog could not be displayed. The primary reason for
 * this separation is to keep this approach for internal use only until we stabilize the API.
 */
public class FacebookWebFallbackDialog extends WebDialog {
    private static final String TAG = FacebookWebFallbackDialog.class.getName();

    public static boolean presentWebFallback(final Context context,
                                             String dialogUrl,
                                             String applicationId,
                                             final FacebookDialog.PendingCall appCall,
                                             final FacebookDialog.Callback callback) {
        if (Utility.isNullOrEmpty(dialogUrl)) {
            return false;
        }

        String redirectUrl = String.format("fb%s://bridge/", applicationId);

        // Show the webdialog.
        FacebookWebFallbackDialog fallbackWebDialog = new FacebookWebFallbackDialog(
                context, dialogUrl, redirectUrl);
        fallbackWebDialog.setOnCompleteListener(new WebDialog.OnCompleteListener() {
            @Override
            public void onComplete(Bundle values, FacebookException error) {
                Intent dummyIntent = new Intent();
                dummyIntent.putExtras(values == null ? new Bundle() : values);
                FacebookDialog.handleActivityResult(
                        context,
                        appCall,
                        appCall.getRequestCode(),
                        dummyIntent,
                        callback);
            }
        });

        fallbackWebDialog.show();
        return true;
    }

    private FacebookWebFallbackDialog(Context context, String url, String expectedRedirectUrl) {
        super(context, url);

        setExpectedRedirectUrl(expectedRedirectUrl);
    }

    @Override
    protected Bundle parseResponseUri(String url) {
        Uri responseUri = Uri.parse(url);
        Bundle queryParams = Utility.parseUrlQueryString(responseUri.getQuery());

        // Convert Bridge args to the format that the Native dialog code understands.
        String bridgeArgsJSONString = queryParams.getString(ServerProtocol.FALLBACK_DIALOG_PARAM_BRIDGE_ARGS);
        queryParams.remove(ServerProtocol.FALLBACK_DIALOG_PARAM_BRIDGE_ARGS);

        if (!Utility.isNullOrEmpty(bridgeArgsJSONString)) {
            Bundle bridgeArgs;
            try {
                JSONObject bridgeArgsJSON = new JSONObject(bridgeArgsJSONString);
                bridgeArgs = BundleJSONConverter.convertToBundle(bridgeArgsJSON);
                queryParams.putBundle(NativeProtocol.EXTRA_PROTOCOL_BRIDGE_ARGS, bridgeArgs);
            } catch (JSONException je) {
                Utility.logd(TAG, "Unable to parse bridge_args JSON", je);
            }
        }

        // Convert Method results to the format that the Native dialog code understands.
        String methodResultsJSONString = queryParams.getString(ServerProtocol.FALLBACK_DIALOG_PARAM_METHOD_RESULTS);
        queryParams.remove(ServerProtocol.FALLBACK_DIALOG_PARAM_METHOD_RESULTS);

        if (!Utility.isNullOrEmpty(methodResultsJSONString)) {
            methodResultsJSONString = Utility.isNullOrEmpty(methodResultsJSONString) ? "{}" : methodResultsJSONString;
            Bundle methodResults;
            try {
                JSONObject methodArgsJSON = new JSONObject(methodResultsJSONString);
                methodResults = BundleJSONConverter.convertToBundle(methodArgsJSON);
                queryParams.putBundle(NativeProtocol.EXTRA_PROTOCOL_METHOD_RESULTS, methodResults);
            } catch (JSONException je) {
                Utility.logd(TAG, "Unable to parse bridge_args JSON", je);
            }
        }

        // The web host does not send a numeric version back. Put the latest known version in there so NativeProtocol
        // can continue parsing the response.
        queryParams.remove(ServerProtocol.FALLBACK_DIALOG_PARAM_VERSION);
        queryParams.putInt(NativeProtocol.EXTRA_PROTOCOL_VERSION, NativeProtocol.getLatestKnownVersion());

        return queryParams;
    }
}
